#include "stdafx.h"

#include "Searcher.h"
#include "SearcheableFileFactory.h"
#include "DirectoryExplorer.h"

#include <map>
#include <iostream>
#include <ctime>

const char STATE[] =  {'-','\\','|','/'};

Searcher::Searcher()
{	
}

Searcher::~Searcher()
{
}


void showResult(std::map<std::set<std::string>, std::set<std::string>*>& resultMap,
				std::multimap<int, std::set<std::string>*>& sortResult);


void deleteMap(std::map<std::set<std::string>, std::set<std::string>*>& resultMap,
			   std::multimap<int, std::set<std::string>*>& sortResult);


void Searcher::search(std::set<std::string>& wordSet, std::string& pathToDir)  
{
	using namespace std;

	searchParameters searchParams = getSearchParameters(wordSet);

	DirectoryExplorer* explorer = new DirectoryExplorer(pathToDir);
	SearcheableFileFactory* factory = new SearcheableFileFactory(pathToDir);

	string file;

	map<set<string>, set<string>*> resultMap;
	multimap<int, set<string>*> sortMap;

	int indexOfState = 0;

	time_t startTime, currentTime;

	time(&startTime);

	while((file = explorer->getNextFile()) != "")
	{		
		if (indexOfState == 4)
		{
			indexOfState = 0;
		}

		cout<< '\r' << "Search in progress" << STATE[indexOfState];

		ISearcheableFile* sFile = factory->createSearcheableFile(file);
		
		if(sFile != NULL)
		{
			indexOfState++;

			set<string>* result = sFile->search(wordSet, searchParams);		

			if (!result->empty())
			{
				map<set<string>, set<string>*>::iterator itToWords = resultMap.find(*result);

				set<string>* filesInMap;
				
				if (itToWords == resultMap.end())
				{		
					filesInMap = new set<string>();
					resultMap.insert(pair<set<string>, set<string>*>(*result, filesInMap));
					sortMap.insert(pair<int, set<string>*>(result->size(), result));
				}
				else
				{
				   filesInMap = itToWords->second;					
				}
				filesInMap->insert(file);
			} 			

			delete(sFile);			
		}
	}

	cout << '\r' << "                                       " << endl;

    time(&currentTime);

	showResult(resultMap, sortMap);

	
	//cout << "time = " << (currentTime - startTime) << " sec"; 
	deleteMap(resultMap, sortMap);

	delete(factory);
	delete(explorer);
}

void showResult(std::map<std::set<std::string>, std::set<std::string>*>& resultMap,
				std::multimap<int, std::set<std::string>*>& sortResult)
{
	using namespace std;

	if (resultMap.empty())
	{
		cout << "Nothing was found";
	}
	else
	{
		for (multimap<int, set<string>*>::reverse_iterator itSortResult = sortResult.rbegin(); 
			itSortResult != sortResult.rend(); itSortResult++) //:TODO
		{
			set<string> words = *(itSortResult->second);
			set<string>* files = resultMap[words];

			for(set<string>::iterator it = words.begin(); it != words.end(); it++)
			{
				cout << (*it) << ' ';
			}

			cout << ':' << files->size() << '\n';

			for(set<string>::iterator it = files->begin(); it != files->end(); it++)
			{
				cout << "          " << (*it) << '\n';
			}
		}
	}
}

void deleteMap(std::map<std::set<std::string>, std::set<std::string>*>& resultMap,
			   std::multimap<int, std::set<std::string>*>& sortResult)
{
	using namespace std;

	for (map<set<string>, set<string>*>::iterator itWords = resultMap.begin(); itWords != resultMap.end(); itWords++)
	{
		delete(itWords->second);
	}

	for (multimap<int, set<string>*>::iterator itSortResult = sortResult.begin(); 
		itSortResult != sortResult.end(); itSortResult++)
	{
		delete(itSortResult->second);
	}
}


searchParameters Searcher::getSearchParameters(std::set<std::string>& wordSet)
{
	using namespace std;
	
	searchParameters params;	

	int minLen = -1;
	int maxLen = 0;

	for(set<string>::iterator iter = wordSet.begin(); iter != wordSet.end(); iter++)
	{
		string s = *iter; 
		
		int currLen = s.length();
		
		if((minLen == -1) || (currLen < minLen))
		{
			minLen = currLen;
		}

		if(currLen > maxLen)
		{
			maxLen = currLen;
		}
	}

	params.minWordLength = minLen;
	params.maxWordLength = maxLen;

	return params;
}


